﻿/* ----------------------------------------------------------------------------
 * Copyright (c) Rob Ashton 2009
 *
 * This source code is subject to terms and conditions of the Microsoft Public 
 * License (Ms-PL).
 * 
 * By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * To request a copy of the Microsoft Public License, send a request by email
 * to license@mvcex.com
 *
 * This notice must not be removed from this software.
 * ---------------------------------------------------------------------------- */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace MvcEx.Configuration
{
    public sealed class MvcExApplicationConfiguration
    {
        #region Private Instance Fields

        private List<MvcExModule> mModules = new List<MvcExModule>();
        private List<MvcExConfiguration> mConfigurations = new List<MvcExConfiguration>();
        private List<String> mThemes = new List<string>();
        
        private XmlSerializer mConfigurationSerializer;
        private XmlSerializer mModuleSerializer;
        
        private String mBaseDir;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the configurations loaded into this application config
        /// </summary>
        public MvcExConfiguration[] Configurations
        {
            get
            {
                return mConfigurations.ToArray();
            }
        }

        /// <summary>
        /// Gets the themes loaded into this application config
        /// </summary>
        public String[] Themes
        {
            get
            {
                return mThemes.ToArray();
            }
        }

        #endregion

        #region .ctor

        private MvcExApplicationConfiguration(String baseDir)
        {
            mConfigurationSerializer = new XmlSerializer(typeof(MvcExConfiguration));
            mModuleSerializer = new XmlSerializer(typeof(MvcExModule));
            mBaseDir = baseDir;
        }

        #endregion

        #region Public Instance Methods

        public void ResetConfiguration()
        {
            // Scan the available modules
            string moduleDirectory = Path.Combine(mBaseDir, MvcExConstants.MODULE_DIRECTORY);
            ScanModules(moduleDirectory);

            // Scan the available themes
            String themeDirectory = Path.Combine(mBaseDir, MvcExConstants.THEME_DIRECTORY);
            ScanThemes(themeDirectory);

            // Scan the available configurations
            string configDirectory = Path.Combine(mBaseDir, MvcExConstants.CONFIG_DIRECTORY);
            ScanConfigurations(configDirectory);
        }

        public MvcExModule GetModuleById(string id)
        {
            return mModules.SingleOrDefault(x => String.Compare(x.Id, id, true) == 0);
        }

        #endregion

        #region Private Instance Methods

        private void ScanConfigurations(string configDirectory)
        {
            mConfigurations.Clear();
            foreach (String file in Directory.GetFiles(configDirectory, "*.xml"))
            {
                using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    MvcExConfiguration configuration = (MvcExConfiguration)mConfigurationSerializer.Deserialize(stream);
                    mConfigurations.Add(configuration);
                }
            }
        }

        private void ScanThemes(string themeDirectory)
        {
            mThemes.Clear();
            foreach (String themeDir in Directory.GetDirectories(themeDirectory))
            {
                mThemes.Add(Path.GetDirectoryName(themeDir));
            }
        }

        private void ScanModules(string moduleDirectory)
        {
            mModules.Clear();
            foreach (String moduleDir in Directory.GetDirectories(moduleDirectory))
            {
                String configFile = Path.Combine(moduleDir, MvcExConstants.MODULE_CONFIG_FILENAME);

                // Ignore invalid folders
                if (!File.Exists(configFile)) { continue; }

                using (var stream = new FileStream(configFile, FileMode.Open, FileAccess.Read))
                {
                    MvcExModule module = (MvcExModule)mModuleSerializer.Deserialize(stream);
                    module.Id = new DirectoryInfo(moduleDir).Name;
                    mModules.Add(module);
                }
            }
        }

        #endregion   

        #region Public Static Methods

        public static MvcExApplicationConfiguration Load(String baseDir)
        {
            var appConfig = new MvcExApplicationConfiguration(baseDir);
            appConfig.ResetConfiguration();
            return appConfig;
        }

        #endregion
    }
}
